package pl.balon.gwt.diagrams.client.connection;

import java.util.LinkedList;
import java.util.List;

import pl.balon.gwt.diagrams.client.connection.calculator.ConnectionDataCalculator;
import pl.balon.gwt.diagrams.client.connection.data.ConnectionData;
import pl.balon.gwt.diagrams.client.connection.data.Point;
import pl.balon.gwt.diagrams.client.connection.pointwidget.HasMoveablePointWidgetCreateEventHandler;
import pl.balon.gwt.diagrams.client.connection.pointwidget.HasMoveablePointWidgetDeleteEventHandler;
import pl.balon.gwt.diagrams.client.connection.pointwidget.HasMoveablePointWidgetMoveEventHandler;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MovePointFactory;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MovePointFactoryImpl;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidget;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetCreateEvent;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetCreateEventHandler;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetDeleteEvent;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetDeleteEventHandler;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetMoveEvent;
import pl.balon.gwt.diagrams.client.connection.pointwidget.MoveablePointWidgetMoveEventHandler;
import pl.balon.gwt.diagrams.client.connector.Connector;

import com.google.gwt.core.client.GWT;
import com.google.gwt.event.shared.GwtEvent;
import com.google.gwt.user.client.ui.AbsolutePanel;
import com.google.gwt.user.client.ui.Widget;

public abstract class AbstractTwoEndedDraggableConnection extends AbstractTwoEndedConnection implements HasMoveablePointWidgetMoveEventHandler, HasMoveablePointWidgetDeleteEventHandler, HasMoveablePointWidgetCreateEventHandler{
	
	public AbstractTwoEndedDraggableConnection(Connector[] toConnect) {
		super(toConnect);
	}

	public List<MoveablePointWidget> getMovablePoint() {
		return this.movablePoints;
	}

	private boolean showMoveablePoints=true;
	
	
	@Override
	public void update() {
		if(this.data == null) {
			super.update();
		}else {
			ConnectionDataCalculator calculator = this.getCalculator();
			this.data = calculator.calculateConnectionData(this.connected, data,-1,0,0);
			this.update(data);
		}
		if(isAttached() && 	isShowMoveablePoints()) {
			movablePointPositions(this.data);
		}
	}
	
	protected List<MoveablePointWidget> movablePoints = new LinkedList<MoveablePointWidget>();
	
	private int changed =-2;
	
	/**
	 * Calculate the place where the movable points will be.
	 * @param data
	 */
	public void movablePointPositions(ConnectionData data){
		List<Point> points = data.getPoints();
		AbsolutePanel panel = (AbsolutePanel) this.getParent();
		int index=0;
		GWT.log("Points:" +data.getPoints().size()+ "Widgets: :"+ movablePoints.size(), null);
		//assert data.getPoints().size()-4==movablePoints.size();
		while(index < movablePoints.size()){
			MoveablePointWidget widgetPoint = this.movablePoints.get(index);
			widgetPoint.setControledIndexPoint(index+2);
			Point p = points.get(widgetPoint.getControledIndexPoint()); 
			if(((Widget) widgetPoint).getParent()!=panel) {
				panel.add((Widget) widgetPoint);
			}
			widgetPoint.setPosition(p.left,p.top);
			index++;
			GWT.log("Widget Point"+ widgetPoint.getControledIndexPoint()+ " Position" + widgetPoint.getLeft() + " " + widgetPoint.getTop(),null);
			GWT.log("Widget w:" + ((Widget)widgetPoint).getOffsetWidth()+" = h:" +((Widget)widgetPoint).getOffsetHeight(), null);
		}
	}
	
	public void addMoveablePointWidgetMoveHandler(MoveablePointWidgetMoveEventHandler handler) {
		addHandler(handler, MoveablePointWidgetMoveEvent.getType());
	}
	
	public void addMoveablePointWidgetDeleteHandler(MoveablePointWidgetDeleteEventHandler handler) {
		addHandler(handler, MoveablePointWidgetDeleteEvent.getType());
	}
	
	public void addMoveablePointWidgetCreateHandler(MoveablePointWidgetCreateEventHandler handler) {
		addHandler(handler, MoveablePointWidgetCreateEvent.getType());
	}
	private MovePointFactory moveablepointFactory = MovePointFactoryImpl.getInstance();
	
	protected MoveablePointWidget createMovableWidget() {
		MoveablePointWidget widget=  moveablepointFactory.createMovablePointWidget(this);
		fireEvent(new MoveablePointWidgetCreateEvent(widget));
		return widget;
	}
	
	
	
	/**
	 * This method set the Factory of the MoveablePointWidget, so you can change the button created.
	 * @param moveablepointFactory
	 */
	public void setMoveablepointFactory(MovePointFactory moveablepointFactory) {
		this.moveablepointFactory = moveablepointFactory;
	}


	@Override
	public void remove() {
		for(MoveablePointWidget w : movablePoints) {
			((Widget) w).removeFromParent();
		}
		super.remove();
	}

	public void setChanged(int changed) {
		this.changed = changed;
	}

	protected int getChanged() {
		return changed;
	}



	@Override
	public void fireEvent(GwtEvent<?> event) {
		if(event.getAssociatedType()==MoveablePointWidgetMoveEvent.getType())
			this.onMovePoint((MoveablePointWidgetMoveEvent) event);
		if(event.getAssociatedType()==MoveablePointWidgetDeleteEvent.getType())
			this.onDeletePoint((MoveablePointWidgetDeleteEvent) event);
		super.fireEvent(event);
	}
	public void onMovePoint(MoveablePointWidgetMoveEvent event) {
			GWT.log("Widget Moved", null);
			ConnectionDataCalculator calculator = this.getCalculator();
			MoveablePointWidget widget = event.getMovePointAction();
			int changed = widget.getControledIndexPoint();
			data.getPoints().get(widget.getControledIndexPoint()).left=widget.getLeft();
			data.getPoints().get(widget.getControledIndexPoint()).top=widget.getTop();
			calculator.calculateConnectionData(this.connected, this.data, changed,widget.getLeft(),widget.getTop());
			this.update(data);
			movablePointPositions(this.data);
	}
	
	public void onDeletePoint(MoveablePointWidgetDeleteEvent event) {
		GWT.log("Widget Deleted", null);
		ConnectionDataCalculator calculator = this.getCalculator();
		MoveablePointWidget widget = event.getMovePointAction();
		int removed = widget.getControledIndexPoint();
		calculator.removePointAndNearestNeighbour(this.connected, removed, this.data);
		calculator.calculateConnectionData(this.connected, this.data, -1,widget.getLeft(),widget.getTop());
		this.update(data);
		movablePointPositions(this.data);
	}

	public void setShowMoveablePoints(boolean showMoveablePoints) {
		this.showMoveablePoints = showMoveablePoints;
	}

	public boolean isShowMoveablePoints() {
		return showMoveablePoints;
	}
	
	

}
